#ifndef YXLOG_H
#define YXLOG_H

#include <errno.h>
#include <stdlib.h>
#include <string.h>

#if defined(__GNUC__) || defined(__clang__)
#define CURRENT_FUNC __PRETTY_FUNCTION__
#elif defined(_MSC_VER)
#define CURRENT_FUNC __FUNCSIG__
#elif defined(__func__)
#define CURRENT_FUNC __func__
#else
#define CURRENT_FUNC "unknown_function"
#endif

#define RESET     "\033[0m"
#define BOLD      "\033[1m"
#define UNDERLINE "\033[4m"

#define BLACK       "\033[30m" /* Black */
#define RED         "\033[31m" /* Red */
#define GREEN       "\033[32m" /* Green */
#define YELLOW      "\033[33m" /* Yellow */
#define BLUE        "\033[34m" /* Blue */
#define MAGENTA     "\033[35m" /* Magenta */
#define CYAN        "\033[36m" /* Cyan */
#define LIGHT_WHITE "\033[97m" /* Light White */

#define YX_LOG_DEBUG   0
#define YX_LOG_INFO    1
#define YX_LOG_WARNING 2
#define YX_LOG_ERROR   3
#define YX_LOG_FATAL   4

#define DEFAULT_YX_LOG_LEVEL YX_LOG_INFO

void  setYXLogLevel(const int level);
void  setYXLogLevelByString(const char *level);
int   getYXLogLevel();
char *getYXLogLevelString();
void  _log(const char *currentFuntion, const int level, const char *text, ...);
void  _throw(const char *file, const int line, const char *text, ...);

#define log(level, text, ...)                                                                                          \
    do {                                                                                                               \
        if (level >= getYXLogLevel()) {                                                                                \
            _log(CURRENT_FUNC, level, text, ##__VA_ARGS__);                                                            \
        }                                                                                                              \
    } while (0)

#define logDebug(text, ...)                                                                                            \
    do {                                                                                                               \
        if (YX_LOG_DEBUG >= getYXLogLevel()) {                                                                         \
            _log(CURRENT_FUNC, YX_LOG_DEBUG, text, ##__VA_ARGS__);                                                     \
        }                                                                                                              \
    } while (0)

#define logInfo(text, ...)                                                                                             \
    do {                                                                                                               \
        if (YX_LOG_INFO >= getYXLogLevel()) {                                                                          \
            _log(CURRENT_FUNC, YX_LOG_INFO, text, ##__VA_ARGS__);                                                      \
        }                                                                                                              \
    } while (0)

#define logWarning(text, ...)                                                                                          \
    do {                                                                                                               \
        if (YX_LOG_WARNING >= getYXLogLevel()) {                                                                       \
            _log(CURRENT_FUNC, YX_LOG_WARNING, text, ##__VA_ARGS__);                                                   \
        }                                                                                                              \
    } while (0)

#define logError(text, ...)                                                                                            \
    do {                                                                                                               \
        if (YX_LOG_ERROR >= getYXLogLevel()) {                                                                         \
            _log(CURRENT_FUNC, YX_LOG_ERROR, text, ##__VA_ARGS__);                                                     \
        }                                                                                                              \
    } while (0)

#define logFatal(text, ...)                                                                                            \
    do {                                                                                                               \
        if (YX_LOG_FATAL >= getYXLogLevel()) {                                                                         \
            _log(CURRENT_FUNC, YX_LOG_FATAL, text, ##__VA_ARGS__);                                                     \
            exit(EXIT_FAILURE);                                                                                        \
        }                                                                                                              \
    } while (0)

#define logErrno()                                                                                                     \
    do {                                                                                                               \
        if (YX_LOG_ERROR >= getYXLogLevel()) {                                                                         \
            _log(CURRENT_FUNC, YX_LOG_ERROR, strerror(errno), NULL);                                                   \
        }                                                                                                              \
    } while (0)

#define logFatalErrno()                                                                                                \
    do {                                                                                                               \
        logFatal(strerror(errno));                                                                                     \
    } while (0)

#define throw(text, ...)                                                                                               \
    do {                                                                                                               \
        _throw(__FILE__, __LINE__, text, ##__VA_ARGS__);                                                               \
    } while (0)

#endif // MTLOG_H
